﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfUMLTry1.Model.Fight;

namespace WpfUMLTry1.Model
{
    public enum FuelType{ RAGE, ENERGY, MANA};
    abstract public class AbstractCreature
    {
        public String name;
        private Int32 _level;
        public Int32 level { get { return _level; } set { if (value < 1) _level = 1; else _level = value; } }
        public Int32 givenExp;
        #region Basic Stats
        private Int32 _bMaxHP;

        private Int32 _bMaxFuel;
        protected FuelType fuel_t;

        private Int32 _bStr;
        private Int32 _bAgi;
        private Int32 _bVit;
        private Int32 _bWis;
        private Int32 _bLuk;

        //Getter - Setter
        public Int32 bMaxHP
        {
            get { return _bMaxHP; }
            set
            {
                _bMaxHP = value;
                CalculateMaxHP();
            }
        }

        public Int32 bMaxFuel
        {
            get { return _bMaxFuel; }
            set
            {
                _bMaxFuel = value;
                maxFuel = _bMaxFuel;
            }
        }

        public Int32 bStr
        {
            get { return _bStr; }
            set
            {
                _bStr = value;
                CalculateStr();
            }
        }
        public Int32 bAgi
        {
            get { return _bAgi; }
            set
            {
                _bAgi = value;
            }
        }
        public Int32 bVit
        {
            get { return _bVit; }
            set
            {
                _bVit = value;
                vit = _bVit;
            }
        }
        public Int32 bWis
        {
            get { return _bWis; }
            set
            {
                _bWis = value;
            }
        }
        public Int32 bLuk
        {
            get { return _bLuk; }
            set
            {
                _bLuk = value;
            }
        }
        #endregion

        protected List<BasicSkill> skillSet;
        public String getSkillName(Int32 index) { return skillSet[index].name; }
        public Int32 getSkillCost(Int32 index) { return skillSet[index].cost; }
        #region private part
        private Int32 _maxHP;
        private Int32 _HP;
        private Int32 _maxFuel;
        private Int32 _fuel;
        private Int32 _str;
        private Int32 _agi;
        private Int32 _vit;
        private Int32 _wis;
        private Int32 _luk;
        private Int32 _experience;

        private Fight.AttackStruct _fullAttack;
        private Int32 _attackDelay;
        #endregion

        public Int32 maxHP
        {
            get { return _maxHP; }
            set { _maxHP = value; }
        }
        public Int32 HP
        {
            get { return _HP; }
            set 
            { 
                _HP = value;
                OnHPModified();
            }
        }
        public Int32 maxFuel
        {
            get { return _maxFuel; }
            set
            {
                _maxFuel = value;
            }
        }
        public Int32 fuel
        {
            get { return _fuel; }
            set
            {
                _fuel = value;
                OnFuelStateChanged();
            }
        }
        public Int32 str
        {
            get { return _str; }
            set
            {
                _str = value;
                AttackDamage = _str;
            }
        }
        public Int32 agi;
        public Int32 vit
        {
            get { return _vit; }
            set
            {
                _vit = value;
                CalculateBaseOfHP();
            }
        }
        public Int32 wis;
        public Int32 luk;

        public Int32 AttackDamage
        {
            get
            {
                return fullAttack.PhisDMGSum();
            }
            set
            {
                fullAttack.SetAttackValue(AttackTypes.Physical, value);
            }

        }

        public virtual Int32 experience
        {
            get { return _experience; }
            set
            {

                _experience = value;
            }
        }

        public Int32 attackDelay
        {
            get { return _attackDelay; }
            set 
            { 
                _attackDelay = value;
                if(_attackDelay <= 0)
                    OnReadyToAttack();
            }
        }

        public AttackStruct fullAttack
        {
            get { return _fullAttack; }
            set { _fullAttack = value; }
        }
        #region Calculated Stats

        public Boolean IsDead{ get { return HP <= 0; } }
        #endregion
       
        #region private calculate basic func.
        private void CalculateBaseOfHP()
        {
            Int32 currMaxHP = maxHP;
            bMaxHP = 5 * vit + level * 5;
            HP += maxHP - currMaxHP;

        }
        private void CalculateMaxHP()
        {
            maxHP = bMaxHP;
        }
        private void CalculateStr()
        {
            str = bStr;
        }
        #endregion

        //Public függvények
        public AbstractCreature(String _name)
        {
            name = _name;
            fullAttack = new AttackStruct();

        }

        #region Setters
        public void SetAllStat(List<Int32> stats)
        {
            if (stats.Count < 5)
                throw new Exception("Not Enough Stat data - SetAllStat");
            bStr = stats[0];
            bAgi = stats[1];
            bVit = stats[2];
            bWis = stats[3];
            bLuk = stats[4];
        }

        #endregion

        public virtual void BasicAttack(AbstractCreature target)
        {
            target.receiveAttack(this, fullAttack);
            attackDelay = basicAttackDelay();
            if (target.IsDead)
            {
                experience += target.givenExp;
                attackDelay = 0;
            }
        }

        public Int32 basicAttackDelay()
        {
            return 20 - agi / 3;
        }

        public virtual void receiveAttack(AbstractCreature source, Fight.AttackStruct AttackIncome)
        {
            HP -= AttackIncome.PhisDMGSum();
            HP -= AttackIncome.MagicDMGSum();
            if (IsDead)
                OnCreatureDead();
        }

        public virtual void fightingTimerElapsed()
        {
            attackDelay -= 1;
        }

        public virtual String getBackSavingText()
        {
            String sStr = String.Empty;

            sStr += name + "|" +
                    _level.ToString() + "|" +
                    givenExp.ToString() + "|" +
                    bMaxHP.ToString() + "|" +
                    bMaxFuel.ToString() + "|" +
                    fuel_t.ToString() + "|" +
                    bStr + "|" +
                    bAgi + "|" +
                    bVit + "|" +
                    bWis + "|" +
                    bLuk + "\n";
            return sStr;
        }

        #region events
        public event EventHandler HPModified;
        public event EventHandler CreatureDead;
        public event EventHandler ReadyToAttack;
        public event EventHandler fuelStateChanged;
        #endregion
        #region Event Callers
        protected void OnHPModified()
        {
            if(HPModified != null)
                HPModified(this, new EventArgs());
        }
        protected void OnCreatureDead()
        {
            if (CreatureDead != null)
                CreatureDead(this, new EventArgs());
        }
        protected void OnReadyToAttack()
        {
            if (ReadyToAttack != null)
                ReadyToAttack(this, new EventArgs());
        }
        protected void OnFuelStateChanged()
        {
            if (fuelStateChanged != null)
                fuelStateChanged(this, new EventArgs());
        }
        protected void setFuelType(String ft)
        {
            if (ft == "RAGE")
                fuel_t = FuelType.RAGE;
            else if (ft == "MANA")
                fuel_t = FuelType.MANA;
            else if (ft == "ENERGY")
                fuel_t = FuelType.ENERGY;
        }
        #endregion
    }
}
